
#include "xapp_config.h"

#if USER_CHECK_ENABLED(SLEEP) && USER_CHECK_ENABLED( PEDOMETER )
// #include "xsdk_config.h"
#include <string.h> 

#include "xapp_sleep.h"
#include "xapp_battery.h"
#include "xapp_clock.h"
#include "xapp_fstore.h"
#include "memory/user_flash_map.h"
#include "xapp_record.h"

#include "xapp_pedometer.h"
#include "xapp_hrs.h"
#include "xapp_profile.h"

#include "array+trim.h"
#include "app_util.h"
#include "watchdata.h"
#include "algo_activities.h"

#if USER_CHECK_LOG_ENABLED( SLEEP )
#include "log.h"
#define LOG     LOG_INFO 
#define LOG0    LOG_INFO0 
#define LOG1    LOG_INFO1
#define LOG2    LOG_INFO2
#define LOG3    LOG_INFO3
#else 
#define LOG(...) 
#define LOG0(...)
#define LOG1(...)
#define LOG2(...)
#define LOG3(...)
#endif 


#if SLEEP_RECORD_ACTIVITY_OF_MINUTE
static detail_activity_t        activityDetail;
static array_trim_data_t        trimActivityDetail;
#endif // !SLEEP_RECORD_ACTIVITY_OF_MINUTE

#if SLEEP_RECORD_ACTIVITY_OF_HOUR
static activity_in_hour_t       __activities_of_hour;
static bool                     flag_activity_in_hour_write = true;
static uint8_t                  __last_activities_hour;
FSTORE_DEF(fs_hour_activity) = FSTORE_HOUR_ACTIVITY_CONFIG();
#endif // !SLEEP_RECORD_ACTIVITY_OF_HOUR

static static_desc_t            staticRecord; 

#if SLEEP_RECORD_POSITION_OF_MINUTE
static detail_position_t        positionDetail;
static array_trim_data_t        trimPositionDetail;
#endif // !SLEEP_RECORD_POSITION_OF_MINUTE

// static xapp_sleep_stash_t   sleepStash; 
static xapp_sleep_record_t  sleepHistRecord;
static xapp_sleep_record_t  sleepCurrRecord;
static bool                     flag_sleep_write = true;
FSTORE_DEF(fs_sleep) = FSTORE_SLEEP_CONFIG();


static algo_sleep_t             algo_sleep;
static bool                     is_updated = false;

static xapp_sleep_desc_t        m_sleep_desc;

static uint8_t sleep_exit(void); 


void xapp_sleep_load_from_profile(void)
{
    xapp_sleep_on_time_update();
}

void xapp_sleep_on_time_update(void)
{
    const datetime_t* dt = xapp_clock_get_now();
    uint16_t hm = dt->hour << 8 | dt->minute;
    const profile_sleep_t* pSleep = xapp_profile_get_SLEEP();

    if( pSleep->start.time > pSleep->stop.time)
    {
        if( hm >= pSleep->start.time || hm <= pSleep->stop.time )
        {
            if( !m_sleep_desc.under_sleep_mode )
            {
                m_sleep_desc.under_sleep_mode = true;
            }
        }
        else 
        {
            if( m_sleep_desc.under_sleep_mode)
            {
                m_sleep_desc.under_sleep_mode = false;
            }
        }
    }
    else if( pSleep->start.time < pSleep->stop.time )
    {
        if( hm >= pSleep->start.time && hm <= pSleep->stop.time )
        {
            if( !m_sleep_desc.under_sleep_mode )
            {
                m_sleep_desc.under_sleep_mode = true;
            }
        }
        else 
        {
            if( m_sleep_desc.under_sleep_mode)
            {
                m_sleep_desc.under_sleep_mode = false;
            }
        }
    }
    else
    {
        m_sleep_desc.under_sleep_mode = true; // always under sleep mode 
    }
}

static void load_sleep_stash(void)
{
    uint8_t data[20];
    datetime_t dt;
    int res = xapp_fstore_recovery_update_record( data, 10, &fs_sleep );
    if( res == 0 ) 
    {
        LOG("[SLEEP]: load_sleep_stash SUCCESS"); 
        flag_sleep_write = false;
        xapp_sleep_stash_t* pstash = (xapp_sleep_stash_t*) data;
        if( rtc_ts_to_datetime( pstash->timestamp, &dt) == 0 ) 
        {
            sleepHistRecord.timestamp = pstash->timestamp;
            sleepHistRecord.WAKEUP = pstash->WAKEUP;
            sleepHistRecord.LIGHT = pstash->LIGHT;
            sleepHistRecord.DEEP = pstash->DEEP;
            sleepHistRecord.TOTAL = pstash->WAKEUP + pstash->LIGHT + pstash->DEEP;
            
            sleepHistRecord.year = dt.year;
            sleepHistRecord.month = dt.month;
            sleepHistRecord.day = dt.day;
            sleepHistRecord.hour = dt.hour;
            sleepHistRecord.minute = dt.minute;            
        }
    }
}

#if SLEEP_RECORD_ACTIVITY_OF_HOUR 
static void load_activity_in_hour_stash(void)
{
    uint8_t data[2*24+4];
    int res = xapp_fstore_recovery_update_record( data, 8, &fs_hour_activity );
    if( res == 0 ) 
    {
        LOG("[SLEEP]: load_activity_in_hour_stash SUCCESS"); 
        flag_activity_in_hour_write = false;
        uint32_t timestamp = uint32_decode( data );
        if( rtc_date_compare( timestamp, xapp_clock_get_timestamp() ) == 0 )
        {
            __activities_of_hour.timestamp = timestamp;
            memcpy( __activities_of_hour.value, data + 4, sizeof(__activities_of_hour.value ) );
        }
        else 
        {
            memset( __activities_of_hour.value, 0, sizeof(__activities_of_hour.value ) );
            __activities_of_hour.timestamp = xapp_clock_get_timestamp();
        }
    }
    else 
    {
        memset( __activities_of_hour.value, 0, sizeof(__activities_of_hour.value ) );
        __activities_of_hour.timestamp = xapp_clock_get_timestamp();
    }  
}
#endif // !SLEEP_RECORD_ACTIVITY_OF_HOUR

static void store_sleep_stash(void)
{
    uint8_t data[10];
    
    uint32_encode( sleepHistRecord.timestamp, data + 0 );
    uint16_encode( sleepHistRecord.WAKEUP, data + 4 );
    uint16_encode( sleepHistRecord.LIGHT, data + 6 );
    uint16_encode( sleepHistRecord.DEEP, data + 8 );
    
    xapp_fstore_data_op_t OP;
    // OP.type = UAFS_DATA_TYPE_SLEEP; 
    OP.len = 10;
    OP.pdata = data;
    // OP.cb = NULL;
    OP.fs = &fs_sleep;
    
    int res ;
    if( flag_sleep_write ) 
    {
        flag_sleep_write = false;
        res = xapp_fstore_store( &OP );
    }
    else 
    {
        res = xapp_fstore_update( &OP );
    }
    if( res != 0 ) 
    {
        // print error 
    }
}
#if SLEEP_RECORD_ACTIVITY_OF_HOUR 
static void store_active_in_hour_stash(void)
{
    uint8_t data[4+sizeof(__activities_of_hour.value)];    
    
    uint32_encode( __activities_of_hour.timestamp, data );
    memcpy( data + 4, (uint8_t*)__activities_of_hour.value, sizeof(__activities_of_hour.value) );
    
    xapp_fstore_data_op_t OP;
    // OP.type = UAFS_DATA_TYPE_ACTIVITY_OF_HOUR;
    OP.pdata = data;
    OP.len = sizeof(data);
    // OP.cb = NULL;
    OP.fs = &fs_hour_activity;
    if( flag_activity_in_hour_write )
    {
        flag_activity_in_hour_write = false;
        xapp_fstore_store( &OP );
    }
    else 
    {
        xapp_fstore_update( &OP );
    }      
}
#endif // !SLEEP_RECORD_ACTIVITY_OF_HOUR

static void store_static_record(void)
{
    if( staticRecord.minutes > 5 )
    {
        uint8_t records[8];
        
        records[0] = 7;
        records[1] = RECORD_DATA_TYPE_STATIC;
        uint32_encode( staticRecord.timestamp, records + 2 );
        uint16_encode( staticRecord.minutes, records + 6 );
        
        xapp_record_store_data( records, 8 ); 
    }
}

#if SLEEP_RECORD_ACTIVITY_OF_MINUTE
static void store_activity_detail(void)
{
    array_data_trim_last_empty( &trimActivityDetail );
    if( trimActivityDetail.len > 0 ) 
    {
        uint8_t data[40];
        
        uint8_t chunk_len = trimActivityDetail.len + 5;
        data[0] = chunk_len;
        data[1] = RECORD_DATA_TYPE_ACTIVITY_IN_MINUTES;
        uint32_encode( activityDetail.timestamp, data + 2 );
        memcpy( data + 6, activityDetail.value, trimActivityDetail.len );
        
        xapp_record_store_data( data, chunk_len + 1 );
    }
}
#endif // !SLEEP_RECORD_ACTIVITY_OF_MINUTE

#if SLEEP_RECORD_POSITION_OF_MINUTE
static void store_position_detail(void)
{
    array_data_trim_last_empty( &trimPositionDetail );
    if( trimPositionDetail.len > 0 )
    {
        uint8_t data[40];

        uint8_t chunk_len = trimPositionDetail.len + 5;
        data[0] = chunk_len;
        data[1] = RECORD_DATA_TYPE_POSITIONS_IN_MINUTES;
        uint32_encode( positionDetail.timestamp, data + 2 );
        memcpy( data + 6, positionDetail.value, trimPositionDetail.len );

        xapp_record_store_data( data, chunk_len + 1 );
    }
}
#endif // !SLEEP_RECORD_POSITION_OF_MINUTE

static void store_sleep(void)
{
    uint8_t data[12];
    
    data[0] = 11;
    data[1] = RECORD_DATA_TYPE_SLEEP;
    uint32_encode( sleepCurrRecord.timestamp, data + 2 );
    uint16_encode( sleepCurrRecord.WAKEUP, data + 6 );
    uint16_encode( sleepCurrRecord.LIGHT, data + 8 );
    uint16_encode( sleepCurrRecord.DEEP, data + 10 );
    
    
    xapp_record_store_data( data, 12 ); 
}

#if SLEEP_RECORD_ACTIVITY_OF_HOUR
static void store_activity_in_hour(void)
{
    uint8_t data[sizeof(__activities_of_hour.value) + 4 + 2];
    
    data[0] = sizeof(__activities_of_hour.value) + 4 + 1;
    data[1] = RECORD_DATA_TYPE_ACTIVITY_OF_HOUR;
    uint32_encode( __activities_of_hour.timestamp, data + 2);    
    memcpy( data + 6, (uint8_t*)__activities_of_hour.value, sizeof(__activities_of_hour.value));
    xapp_record_store_data( data, sizeof(data ) );     
}
#endif // !SLEEP_RECORD_ACTIVITY_OF_HOUR


static void detail_process(uint8_t activity, uint8_t positions)
{    
#if SLEEP_RECORD_ACTIVITY_OF_HOUR    // 小时活动计数 存储
    int idx = __last_activities_hour;
    if( idx < 24 ) 
    {
        __activities_of_hour.value[idx] += activity;
    }
    __last_activities_hour = xapp_clock_get_now()->hour; 
#endif // !SLEEP_RECORD_ACTIVITY_OF_HOUR    

#if SLEEP_RECORD_ACTIVITY_OF_MINUTE    // 每分钟记录 追加活动计数
    array_trim_data_enqueue_byte( &trimActivityDetail, activity );
    
    // 第一个数据为0值，不保存，更新时间戳
    if( trimActivityDetail.stage == ARRAY_TRIM_STAGE_WAIT ) 
    {
        activityDetail.timestamp = xapp_clock_get_timestamp();
    }
    else if( trimActivityDetail.stage == ARRAY_TRIM_STAGE_FULL ) // 数据满了，保存，清除队列
    {
        store_activity_detail();
        array_trim_reset( &trimActivityDetail );
    }
#endif // !SLEEP_RECORD_ACTIVITY_OF_MINUTE

#if SLEEP_RECORD_POSITION_OF_MINUTE    // 每分钟记录 追加翻身记录
    array_trim_data_enqueue_byte( &trimPositionDetail, positions );
    if( trimPositionDetail.stage == ARRAY_TRIM_STAGE_WAIT )
    {
        positionDetail.timestamp = xapp_clock_get_timestamp();
    }
    else if( trimPositionDetail.stage == ARRAY_TRIM_STAGE_FULL )
    {
        store_position_detail();
        array_trim_reset( &trimPositionDetail );
    }
#endif // !SLEEP_RECORD_POSITION_OF_MINUTE
    
    // 静止处理
    if( activity == 0 && positions == 0 ) 
    {
        staticRecord.minutes ++;       
        if( staticRecord.minutes > SLEEP_THRESHOLD_OF_STATIC_SAVE_AUTO ) // 10 days 
        {
            store_static_record();
            staticRecord.minutes = 0;
            staticRecord.timestamp = xapp_clock_get_timestamp();
        }
        // 连续静止超过指定时间长，退出睡眠
        if( algo_sleep.fsm != ALGO_SLEEP_STATE_ENTER && staticRecord.minutes > (60 * 2) )
        {
            /*uint8_t have_history_data=sleep_exit(); */
            algo_sleep_init( &algo_sleep, xapp_clock_get_timestamp );
//            if(have_history_data)//解决未佩戴也有睡眠数据
//            {
//                algo_sleep.timestamp = sleepCurrRecord.timestamp ;
//                algo_sleep.wakeup = sleepCurrRecord.WAKEUP ;
//                algo_sleep.light = sleepCurrRecord.LIGHT ;
//                algo_sleep.deep = sleepCurrRecord.DEEP ;
//            }
        }        
    }
    else 
    {
        if( staticRecord.minutes > SLEEP_THRESHOLD_OF_STATIC ) 
        {
            store_static_record();
        }
        staticRecord.minutes = 0;
        staticRecord.timestamp = xapp_clock_get_timestamp();
    }

}

static uint8_t sleep_exit(void)
{
    uint16_t sum = algo_sleep.wakeup + algo_sleep.light + algo_sleep.deep;
    if( sum < SLEEP_THRESHOLD_OF_VALID_RECORD ) 
    {
        return 0;
    }

    uint16_t active_count = algo_sleep.wakeup + algo_sleep.light;
    if( active_count < SLEEP_MINI_ACTIVE_TIME_REQUIRED || (active_count < sum / SLEEP_MINI_ACTIVE_PERCENT_REQUIRED))
    {
        return 0;
    }

    sleepCurrRecord.timestamp = algo_sleep.timestamp;
    sleepCurrRecord.WAKEUP = algo_sleep.wakeup;
    sleepCurrRecord.LIGHT = algo_sleep.light;
    sleepCurrRecord.DEEP = algo_sleep.deep;
    sleepCurrRecord.TOTAL = sum;

    datetime_t dt;
    rtc_ts_to_datetime(algo_sleep.timestamp, &dt );
    sleepCurrRecord.year = dt.year;
    sleepCurrRecord.month = dt.month;
    sleepCurrRecord.day = dt.day;
    sleepCurrRecord.hour = dt.hour;
    sleepCurrRecord.minute = dt.minute;

    // 拷贝历史记录
    memcpy( &sleepHistRecord, &sleepCurrRecord, sizeof(sleepCurrRecord) );

    store_sleep();
    return 1;
}

void xapp_sleep_clear(void)
{
    uint32_t timestamp = xapp_clock_get_timestamp();
    memset( &sleepCurrRecord, 0, sizeof(sleepCurrRecord));
    memset( &sleepHistRecord, 0, sizeof(sleepHistRecord));

#if SLEEP_RECORD_ACTIVITY_OF_HOUR
    memset( &__activities_of_hour, 0, sizeof(__activities_of_hour));
    __activities_of_hour.timestamp = timestamp;
#endif 
    
    algo_sleep_init( &algo_sleep, xapp_clock_get_timestamp );

#if SLEEP_RECORD_ACTIVITY_OF_MINUTE
    array_trim_reset( &trimActivityDetail );
    activityDetail.timestamp = timestamp;
#endif // !SLEEP_RECORD_ACTIVITY_OF_MINUTE

#if SLEEP_RECORD_POSITION_OF_MINUTE
    array_trim_reset( &trimPositionDetail );    
    positionDetail.timestamp = timestamp;
#endif // !SLEEP_RECORD_POSITION_OF_MINUTE

    staticRecord.minutes = 0;
    staticRecord.timestamp = timestamp;
    
}

void xapp_sleep_on_time_change(uint8_t flag)
{
    rtc_flag_t* f = (rtc_flag_t*)&flag;
    const xapp_pedo_desc_t* pdesc = xapp_pedometer_get_desc();
    if( pdesc->activities_of_minute > 0 )
    {
        is_updated = true;
    }

    // 处理活动计数(上一分钟的活动计数更新)
    detail_process( pdesc->activities_of_minute, pdesc->position_of_minute );

    if( f->bit.minute_skip > 0 ) 
    {       
        xapp_sleep_on_time_update();

        // 退出睡眠
        if( algo_sleep.fsm != ALGO_SLEEP_STATE_ENTER )
        {
            sleep_exit(); 
        }
        // 清除睡眠
        algo_sleep_init( &algo_sleep, xapp_clock_get_timestamp );
        
#if SLEEP_RECORD_ACTIVITY_OF_MINUTE        // 保存连续活动计数
        store_activity_detail();
        array_trim_reset( &trimActivityDetail );
#endif // !SLEEP_RECORD_ACTIVITY_OF_MINUTE
#if SLEEP_RECORD_POSITION_OF_MINUTE
        store_position_detail();
        array_trim_reset( &trimPositionDetail );
#endif // !SLEEP_RECORD_POSITION_OF_MINUTE

        // 保存静止记录
        store_static_record();  
        staticRecord.minutes = 0;
        staticRecord.timestamp = xapp_clock_get_timestamp();
    }    
    else if( f->bit.minute > 0 ) 
    {
        xapp_sleep_on_time_update();

        // 如果充电，清除睡眠数据
        if( xapp_battery_get_desc()->charging )
        {
            if( algo_sleep.fsm != ALGO_SLEEP_STATE_ENTER )
            {
                sleep_exit();
                algo_sleep_init( &algo_sleep, xapp_clock_get_timestamp );
            }            
        }

        algo_record_t rec;
        rec.cnt_of_position     = pdesc->position_of_minute; 
        rec.cnt_of_activities   = pdesc->activities_of_minute; 
        rec.cnt_of_steps        = pdesc->steps_of_minute; 

#if SLEEP_DETECT_SPECIFY_TIME_RANGE // 指定睡眠监测范围，若不指定，则为全天监测
        

#if SLEEP_TIME_SEGMENT_TYPE == 0 
//////////////////////////////////////////////////////////////////////////
        const datetime_t* pdt = xapp_clock_get_now();
#if( SLEEP_DETECT_TIME_START_HOUR > SLEEP_DETECT_TIME_STOP_HOUR )
        if( pdt->hour > SLEEP_DETECT_TIME_START_HOUR || pdt->hour < SLEEP_DETECT_TIME_STOP_HOUR || algo_sleep.fsm > ALGO_SLEEP_STATE_ENTER )
#elif( SLEEP_DETECT_TIME_START_HOUR < SLEEP_DETECT_TIME_STOP_HOUR )
        if( (pdt->hour > SLEEP_DETECT_TIME_START_HOUR && pdt->hour < SLEEP_DETECT_TIME_STOP_HOUR) || algo_sleep.fsm > ALGO_SLEEP_STATE_ENTER )
#else 
        #error "sleep detect time start SHOULD-NOT equal time stop"
#endif // !SLEEP_TIME_SEGMENT_TYPE == 0 
//////////////////////////////////////////////////////////////////////////
#elif SLEEP_TIME_SEGMENT_TYPE == 1 
//////////////////////////////////////////////////////////////////////////
        if( m_sleep_desc.under_sleep_mode || algo_sleep.fsm > ALGO_SLEEP_STATE_ENTER )
//////////////////////////////////////////////////////////////////////////        
#else 
//////////////////////////////////////////////////////////////////////////
#error "sleep detect time met UNKNOW condition" 
        if( algo_sleep.fsm > ALGO_SLEEP_STATE_ENTER )
//////////////////////////////////////////////////////////////////////////
#endif 
        {            
            if(xapp_hrs_is_wear())
            {
                algo_sleep_process( &algo_sleep, &rec,  xapp_clock_get_timestamp );

                if( algo_sleep.fsm == ALGO_SLEEP_STATE_EXIT )
                {
                    uint8_t have_history_data=sleep_exit(); 
                    algo_sleep_init( &algo_sleep, xapp_clock_get_timestamp );
                    if(have_history_data)
                    {
                        algo_sleep.timestamp = sleepCurrRecord.timestamp ;
                        algo_sleep.wakeup = sleepCurrRecord.WAKEUP ;
                        algo_sleep.light = sleepCurrRecord.LIGHT ;
                        algo_sleep.deep = sleepCurrRecord.DEEP ;
                    }
                }
            }
        }
        else 
        {
            algo_sleep_init( &algo_sleep, xapp_clock_get_timestamp );
        }
#else 
        if(xapp_hrs_is_wear())
        {
            algo_sleep_process( &algo_sleep, &rec,  xapp_clock_get_timestamp );
            if( algo_sleep.fsm == ALGO_SLEEP_STATE_EXIT )
            {
                uint8_t have_history_data=sleep_exit(); 
                algo_sleep_init( &algo_sleep, xapp_clock_get_timestamp );
                if(have_history_data)
                {
                    algo_sleep.timestamp = sleepCurrRecord.timestamp ;
                    algo_sleep.wakeup = sleepCurrRecord.WAKEUP ;
                    algo_sleep.light = sleepCurrRecord.LIGHT ;
                    algo_sleep.deep = sleepCurrRecord.DEEP ;
                }
            }
        }
#endif 
    }
    
    if( f->bit.date > 0 )
    {
#if SLEEP_RECORD_ACTIVITY_OF_HOUR
        store_activity_in_hour();
#endif // !SLEEP_RECORD_ACTIVITY_OF_HOUR

    }
}

const xapp_sleep_record_t* xapp_sleep_get(void)
{
    sleepCurrRecord.TOTAL = algo_sleep.wakeup + algo_sleep.light + algo_sleep.deep;
                          //sleepCurrRecord.WAKEUP + sleepCurrRecord.LIGHT + sleepCurrRecord.DEEP;
    
    if( sleepCurrRecord.TOTAL > 60 ) 
    {
        sleepCurrRecord.WAKEUP = algo_sleep.wakeup;
        sleepCurrRecord.LIGHT = algo_sleep.light;
        sleepCurrRecord.DEEP = algo_sleep.deep;

        if( sleepCurrRecord.timestamp != algo_sleep.timestamp )
        {
            datetime_t dt;
            sleepCurrRecord.timestamp = algo_sleep.timestamp;
            rtc_ts_to_datetime( algo_sleep.timestamp, &dt );
            sleepCurrRecord.month = dt.month;
            sleepCurrRecord.day = dt.day;
            sleepCurrRecord.hour = dt.hour;
            sleepCurrRecord.minute = dt.minute;
        }
        
        return &sleepCurrRecord;
    }
    
//    if( sleepHistRecord.timestamp == 0 ) 
//    {
//        return NULL;
//    }
    
    return xapp_sleep_get_yestoday_to_today();
}

const xapp_sleep_record_t* xapp_sleep_get_yestoday_to_today(void)
{
    datetime_t dt = *xapp_clock_get_now();

    #if SLEEP_ADD_TEST_SLEEP_DATA // test example 
    xapp_sleep_record_t tmp = SLEEP_HIST_RECORD_TEST;
    memcpy( &sleepHistRecord, &tmp, sizeof(xapp_sleep_record_t ));
    return &sleepHistRecord;
    #else

    // 同一天的数据
    if( dt.year == sleepHistRecord.year && dt.month == sleepHistRecord.month && dt.day == sleepHistRecord.day )
    {
        if( sleepHistRecord.hour < 19 )
        {
            // 当前数据可以显示
            return &sleepHistRecord;
        }
    }
    rtc_date_dec( &dt );
    // 为昨天的数据
    if( dt.year == sleepHistRecord.year && dt.month == sleepHistRecord.month && dt.day == sleepHistRecord.day )
    {
        if( sleepHistRecord.hour >= 19 )
        {
            // 当前数据可以显示 
            return &sleepHistRecord; 
        }
    }

    return NULL;
    #endif // !SLEEP_ADD_TEST_SLEEP_DATA
}


void xapp_sleep_init(void)
{
    uint32_t timestamp = xapp_clock_get_timestamp();
#if SLEEP_RECORD_ACTIVITY_OF_MINUTE
    memset( &trimActivityDetail, 0, sizeof(array_trim_data_t) );
    trimActivityDetail.param.u8 = activityDetail.value;
    activityDetail.timestamp    = timestamp; 
#endif // !SLEEP_RECORD_ACTIVITY_OF_MINUTE

#if SLEEP_RECORD_POSITION_OF_MINUTE
    memset( &trimPositionDetail, 0, sizeof(array_trim_data_t) );
    trimPositionDetail.param.u8 = positionDetail.value;
    positionDetail.timestamp    = timestamp;
#endif // !SLEEP_RECORD_POSITION_OF_MINUTE
    
    load_sleep_stash();
#if SLEEP_RECORD_ACTIVITY_OF_HOUR
    load_activity_in_hour_stash();
    __last_activities_hour      = xapp_clock_get_now()->hour; 
    m_sleep_desc.p_activity_of_hour = __activities_of_hour.value;
#endif // !SLEEP_RECORD_ACTIVITY_OF_HOUR
    
 
    staticRecord.timestamp      = timestamp;    
    algo_sleep_init( &algo_sleep, xapp_clock_get_timestamp );

    #if 0 // test
    const datetime_t* pdt = xapp_clock_get_now();
    // algo_sleep.timestamp = 0;
    algo_sleep.wakeup = 100;
    algo_sleep.light = 120;
    algo_sleep.deep = 180;

    sleep_exit();
    // store_sleep_stash();

    #endif 
}

void xapp_sleep_stop(void)
{
    // 睡眠记录
    sleep_exit(); 

    if( is_updated )
    {
        is_updated = false; 
        
        // 上次历史记录暂存 
        store_sleep_stash();
#if SLEEP_RECORD_ACTIVITY_OF_HOUR        
        // 当前每小时活动计数暂存 
        store_active_in_hour_stash();
#endif 
        // 每小时活动计数
        // store_activity_in_hour();
    }
    // 保存静止时长 
    store_static_record();
}

const xapp_sleep_desc_t* xapp_sleep_get_desc(void)
{
    return &m_sleep_desc; 
}


//for location
bool xapp_sleep_is_sleep_status(void)
{
    return m_sleep_desc.under_sleep_mode;
}

uint16_t xapp_sleep_get_light_time(void)
{
    xapp_sleep_record_t const* p_sleep = xapp_sleep_get();
    if(p_sleep)
    {
    return p_sleep->LIGHT+p_sleep->WAKEUP/2;
    }
    else
    {
    return 0;
    }
}
uint16_t xapp_sleep_get_deep_time(void)
{
    xapp_sleep_record_t const* p_sleep = xapp_sleep_get();
    if(p_sleep)
    {
    return p_sleep->DEEP+p_sleep->WAKEUP/2;
    }
    else
    {
    return 0;
    }
}

#define SLEEP_S_WAKEUP  0    //佩戴未睡
#define SLEEP_S_LIGHT   1    //佩戴浅睡
#define SLEEP_S_DEEP    2    //佩戴深睡
#define SLEEP_S_UNKNOW  0xff //未佩戴

uint16_t xapp_sleep_get_sleep_status(void)
{
    if(!xapp_hrs_is_wear())
    {
        return SLEEP_S_UNKNOW;
    }
    else //if(xapp_sleep_is_sleep_status())
    {
        if(algo_sleep.fsm == ALGO_SLEEP_STATE_EXIT || algo_sleep.fsm == ALGO_SLEEP_STATE_ENTER)
            return SLEEP_S_WAKEUP;
        else if(algo_sleep.fsm == ALGO_SLEEP_STATE_DEEP)
            return SLEEP_S_DEEP;
        else //if(algo_sleep.fsm <= ALGO_SLEEP_STATE_LIGHT)
            return SLEEP_S_LIGHT;
    }
//    else
//    {
//        return SLEEP_S_WAKEUP;//??
//    }
}

#endif // !USER_CHECK_ENABLED( SLEEP )
